package com.knowledgeqa.system.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;

import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                // 配置CORS
                .cors().configurationSource(corsConfigurationSource())
                .and()
                // 禁用CSRF（对于API来说通常禁用）
                .csrf().disable()
                // 配置异常处理
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint())
                .accessDeniedHandler(accessDeniedHandler())
                .and()
                // 配置会话管理
                .sessionManagement()
                .maximumSessions(1)
                .maxSessionsPreventsLogin(false)
                .and()
                .and()
                // 配置授权规则
                .authorizeRequests()
                // 公开访问路径
                .antMatchers("/api/public/**", "/auth/**", "/error", "/actuator/**").permitAll()
                // 管理员路径需要ADMIN角色
                .antMatchers("/admin/**", "/api/admin/**").hasRole("ADMIN")
                // 用户路径需要USER或ADMIN角色
                .antMatchers("/api/user/**", "/user/**").hasAnyRole("USER", "ADMIN")
                // 其他所有请求都需要认证
                .anyRequest().authenticated()
                .and()
                // 配置表单登录
                .formLogin()
                .loginProcessingUrl("/auth/login")
                .successHandler(authenticationSuccessHandler())
                .failureHandler(authenticationFailureHandler())
                .permitAll()
                .and()
                // 配置登出
                .logout()
                .logoutUrl("/auth/logout")
                .logoutSuccessHandler(logoutSuccessHandler())
                .permitAll()
                .and()
                // 配置记住我功能
                .rememberMe()
                .key("knowledgeQARememberMeKey")
                .tokenValiditySeconds(24 * 60 * 60); // 24小时
    }

    /**
     * 配置CORS跨域设置
     * @return CorsConfigurationSource
     */
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowedOriginPatterns(Arrays.asList("*"));
        configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
        configuration.setAllowedHeaders(Arrays.asList("*"));
        configuration.setAllowCredentials(true);
        configuration.setMaxAge(3600L);

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);
        return source;
    }

    /**
     * 认证成功处理器
     * @return AuthenticationSuccessHandler
     */
    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":200,\"message\":\"登录成功\",\"data\":{\"username\":\""
                    + authentication.getName() + "\"}}");
        };
    }

    /**
     * 认证失败处理器
     * @return AuthenticationFailureHandler
     */
    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return (request, response, exception) -> {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"用户名或密码错误\"}");
        };
    }

    /**
     * 登出成功处理器
     * @return LogoutSuccessHandler
     */
    @Bean
    public LogoutSuccessHandler logoutSuccessHandler() {
        return (request, response, authentication) -> {
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":200,\"message\":\"登出成功\"}");
        };
    }

    /**
     * 未认证访问处理器
     * @return AuthenticationEntryPoint
     */
    @Bean
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request, response, authException) -> {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":401,\"message\":\"请先登录\"}");
        };
    }

    /**
     * 权限不足处理器
     * @return AccessDeniedHandler
     */
    @Bean
    public AccessDeniedHandler accessDeniedHandler() {
        return (request, response, accessDeniedException) -> {
            response.setStatus(HttpServletResponse.SC_FORBIDDEN);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"code\":403,\"message\":\"权限不足\"}");
        };
    }

    /**
     * 密码编码器
     * @return PasswordEncoder
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 用户权限验证服务
     * 这里提供一个基础实现，实际项目中需要根据数据库查询用户信息
     */
    public class UserDetailsServiceImpl implements org.springframework.security.core.userdetails.UserDetailsService {

        @Override
        public org.springframework.security.core.userdetails.UserDetails loadUserByUsername(String username)
                throws org.springframework.security.core.userdetails.UsernameNotFoundException {

            // 在实际应用中，这里应该从数据库查询用户信息
            // 暂时返回一个默认用户用于演示
            if ("admin".equals(username)) {
                return org.springframework.security.core.userdetails.User.builder()
                        .username("admin")
                        .password(passwordEncoder().encode("admin123"))
                        .roles("ADMIN")
                        .build();
            } else if ("user".equals(username)) {
                return org.springframework.security.core.userdetails.User.builder()
                        .username("user")
                        .password(passwordEncoder().encode("user123"))
                        .roles("USER")
                        .build();
            } else {
                throw new org.springframework.security.core.userdetails.UsernameNotFoundException("用户不存在");
            }
        }
    }

    /**
     * JWT工具类
     * 用于生成和验证JWT token
     */
    public static class JwtUtil {
        private static final String SECRET_KEY = "knowledgeQA_secret_key";
        private static final long EXPIRATION_TIME = 86400000; // 24小时

        /**
         * 生成JWT token
         * @param username 用户名
         * @return JWT token
         */
        public static String generateToken(String username) {
            // 实际项目中这里需要实现JWT生成逻辑
            // 为简化代码，这里直接返回用户名
            return username + "_token";
        }

        /**
         * 验证JWT token
         * @param token JWT token
         * @return 用户名
         */
        public static String validateToken(String token) {
            // 实际项目中这里需要实现JWT验证逻辑
            // 为简化代码，这里直接从token中提取用户名
            if (token != null && token.contains("_token")) {
                return token.substring(0, token.indexOf("_token"));
            }
            return null;
        }
    }

    /**
     * 安全工具类
     * 提供常用的安全相关方法
     */
    public static class SecurityUtils {

        /**
         * 获取当前认证用户
         * @return 当前用户信息
         */
        public static org.springframework.security.core.Authentication getCurrentAuthentication() {
            return org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication();
        }

        /**
         * 获取当前用户名
         * @return 当前用户名
         */
        public static String getCurrentUsername() {
            org.springframework.security.core.Authentication authentication = getCurrentAuthentication();
            if (authentication != null && authentication.getPrincipal() instanceof org.springframework.security.core.userdetails.UserDetails) {
                return ((org.springframework.security.core.userdetails.UserDetails) authentication.getPrincipal()).getUsername();
            }
            return null;
        }

        /**
         * 检查当前用户是否具有指定角色
         * @param role 角色名
         * @return 是否具有该角色
         */
        public static boolean hasRole(String role) {
            org.springframework.security.core.Authentication authentication = getCurrentAuthentication();
            if (authentication != null) {
                return authentication.getAuthorities().stream()
                        .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_" + role));
            }
            return false;
        }

        /**
         * 检查当前用户是否已认证
         * @return 是否已认证
         */
        public static boolean isAuthenticated() {
            org.springframework.security.core.Authentication authentication = getCurrentAuthentication();
            return authentication != null && authentication.isAuthenticated()
                    && !"anonymousUser".equals(authentication.getPrincipal());
        }
    }

    /**
     * 自定义过滤器
     * 用于处理JWT认证
     */
    public static class JwtAuthenticationFilter extends org.springframework.web.filter.OncePerRequestFilter {

        @Override
        protected void doFilterInternal(
                javax.servlet.http.HttpServletRequest request,
                javax.servlet.http.HttpServletResponse response,
                javax.servlet.FilterChain filterChain)
                throws java.io.IOException, javax.servlet.ServletException {

            String token = extractToken(request);
            if (token != null) {
                String username = JwtUtil.validateToken(token);
                if (username != null &&
                        org.springframework.security.core.context.SecurityContextHolder.getContext().getAuthentication() == null) {

                    // 在实际应用中，这里应该从数据库加载用户详细信息
                    org.springframework.security.core.userdetails.UserDetails userDetails =
                            new org.springframework.security.core.userdetails.User(username, "",
                                    java.util.Collections.singletonList(
                                            new org.springframework.security.core.authority.SimpleGrantedAuthority("ROLE_USER")));

                    org.springframework.security.authentication.UsernamePasswordAuthenticationToken authentication =
                            new org.springframework.security.authentication.UsernamePasswordAuthenticationToken(
                                    userDetails, null, userDetails.getAuthorities());

                    authentication.setDetails(new org.springframework.security.web.authentication.WebAuthenticationDetailsSource().buildDetails(request));
                    org.springframework.security.core.context.SecurityContextHolder.getContext().setAuthentication(authentication);
                }
            }

            filterChain.doFilter(request, response);
        }

        /**
         * 从请求中提取JWT token
         * @param request HTTP请求
         * @return JWT token
         */
        private String extractToken(javax.servlet.http.HttpServletRequest request) {
            String bearerToken = request.getHeader("Authorization");
            if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
                return bearerToken.substring(7);
            }
            return null;
        }
    }

    /**
     * 自定义认证提供者
     * 可以扩展默认的认证逻辑
     */
    public static class CustomAuthenticationProvider implements org.springframework.security.authentication.AuthenticationProvider {

        private final org.springframework.security.core.userdetails.UserDetailsService userDetailsService;
        private final PasswordEncoder passwordEncoder;

        public CustomAuthenticationProvider(
                org.springframework.security.core.userdetails.UserDetailsService userDetailsService,
                PasswordEncoder passwordEncoder) {
            this.userDetailsService = userDetailsService;
            this.passwordEncoder = passwordEncoder;
        }

        @Override
        public org.springframework.security.core.Authentication authenticate(org.springframework.security.core.Authentication authentication)
                throws org.springframework.security.core.AuthenticationException {

            String username = authentication.getName();
            String password = authentication.getCredentials().toString();

            org.springframework.security.core.userdetails.UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            if (userDetails != null && passwordEncoder.matches(password, userDetails.getPassword())) {
                return new org.springframework.security.authentication.UsernamePasswordAuthenticationToken(
                        userDetails, password, userDetails.getAuthorities());
            }

            throw new org.springframework.security.core.AuthenticationException("认证失败") {};
        }

        @Override
        public boolean supports(Class<?> authentication) {
            return org.springframework.security.authentication.UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
        }
    }

    /**
     * 安全元数据源
     * 用于动态配置URL权限
     */
    public static class CustomSecurityMetadataSource implements org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource {

        private final java.util.Map<String, java.util.List<org.springframework.security.access.ConfigAttribute>> urlRolesMap =
                new java.util.HashMap<>();

        public CustomSecurityMetadataSource() {
            // 初始化URL角色映射
            initUrlRolesMapping();
        }

        private void initUrlRolesMapping() {
            // 在实际应用中，这些映射应该从数据库加载
            urlRolesMap.put("/admin/**", java.util.Arrays.asList(
                    new org.springframework.security.access.SecurityConfig("ROLE_ADMIN")));
            urlRolesMap.put("/api/user/**", java.util.Arrays.asList(
                    new org.springframework.security.access.SecurityConfig("ROLE_USER"),
                    new org.springframework.security.access.SecurityConfig("ROLE_ADMIN")));
        }

        @Override
        public java.util.Collection<org.springframework.security.access.ConfigAttribute> getAttributes(Object object)
                throws org.springframework.security.access.SecurityConfigException {

            javax.servlet.http.HttpServletRequest request =
                    ((org.springframework.security.web.FilterInvocation) object).getRequest();

            String requestUrl = request.getRequestURI();

            // 在实际应用中，这里应该实现URL匹配逻辑
            for (java.util.Map.Entry<String, java.util.List<org.springframework.security.access.ConfigAttribute>> entry : urlRolesMap.entrySet()) {
                if (requestUrl.matches(entry.getKey().replace("**", ".*").replace("*", "[^/]*"))) {
                    return entry.getValue();
                }
            }

            // 默认情况下，所有认证用户都可以访问
            return java.util.Collections.singletonList(
                    new org.springframework.security.access.SecurityConfig("ROLE_USER"));
        }

        @Override
        public java.util.Collection<org.springframework.security.access.ConfigAttribute> getAllConfigAttributes() {
            return null;
        }

        @Override
        public boolean supports(Class<?> clazz) {
            return org.springframework.security.web.FilterInvocation.class.isAssignableFrom(clazz);
        }
    }

    /**
     * 安全配置构建器
     * 用于构建复杂的安全配置
     */
    public static class SecurityConfigBuilder {
        private boolean enableCors = true;
        private boolean enableCsrf = false;
        private String[] permitAllPaths = {"/auth/**", "/error"};
        private java.util.Map<String, String[]> rolePaths = new java.util.HashMap<>();

        public SecurityConfigBuilder enableCors(boolean enable) {
            this.enableCors = enable;
            return this;
        }

        public SecurityConfigBuilder enableCsrf(boolean enable) {
            this.enableCsrf = enable;
            return this;
        }

        public SecurityConfigBuilder permitAllPaths(String... paths) {
            this.permitAllPaths = paths;
            return this;
        }

        public SecurityConfigBuilder rolePaths(String role, String... paths) {
            this.rolePaths.put(role, paths);
            return this;
        }

        public SecurityConfig build() {
            // 实际项目中这里会返回一个配置好的SecurityConfig实例
            return new SecurityConfig();
        }
    }
}
